using System;
using System.Threading;

using TrueCode.Core.Diagnostics;

namespace TrueCode.Core.Threading
{
	public enum AcquireLock
	{
		Reader,
		Writer
	}

	/// <summary>
	/// This class is not thread safe
	/// </summary>
	public class UniversalLock : IDisposable
	{
		private readonly ReaderWriterLock _lockObject;

		private LockCookie? _upgradeCookie;


		public UniversalLock( ReaderWriterLock lockObject ) : this( lockObject, AcquireLock.Reader )
		{
			
		}

		public UniversalLock( ReaderWriterLock lockObject, AcquireLock lockType )
		{
			#region Validation
			if(!DebugAssert.IsNotNull(lockObject, "lockObject"))
			{
				throw new Exception<UniversalLock, ArgumentNullException>(new ArgumentNullException("lockObject"));
			}
			#endregion


			_lockObject = lockObject;

			switch( lockType )
			{
				case AcquireLock.Reader:
					_lockObject.AcquireReaderLock( -1 );
					break;
				case AcquireLock.Writer:
					_lockObject.AcquireWriterLock( -1 );
					break;
				default:
					throw new Exception< UniversalLock, ArgumentException >( new ArgumentException( "Invalid lock type", "lockType" ) );
			}
		}

		public void Upgrade()
		{
			_upgradeCookie = _lockObject.UpgradeToWriterLock( -1 );
		}

		public void Downgrade()
		{
			#region Validation
			if( ! DebugAssert.IsNotNull( _upgradeCookie ) )
			{
				throw new Exception<UniversalLock, InvalidOperationException>( new InvalidOperationException( "The thread did not upgrade to writer lock." ) );
			}
			#endregion


			LockCookie lockCookie = _upgradeCookie.Value;
			_lockObject.DowngradeFromWriterLock( ref lockCookie );
			_upgradeCookie = null;
		}


		public void Dispose( )
		{
			_lockObject.ReleaseLock( );
		}
	}
}
